<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>springcloud之Gateway | rongshen</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  
  
<link rel="stylesheet" href="/css/style.css">

  
    
<link rel="stylesheet" href="/css/highlight.css">

  
  <meta name="description" content="springcloud学习笔记，第7章，Gateway微服务网关。">
<meta property="og:type" content="article">
<meta property="og:title" content="springcloud之Gateway">
<meta property="og:url" content="http://example.com/2020/09/28/springcloud%E4%B9%8BGateway/index.html">
<meta property="og:site_name" content="rongshen">
<meta property="og:description" content="springcloud学习笔记，第7章，Gateway微服务网关。">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a1.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a2.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a3.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a4.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a5.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a6.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a7.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a8.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a9.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a10.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a11.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a12.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a13.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a14.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a15.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a16.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a17.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a18.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a19.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a20.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a21.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a22.png">
<meta property="og:image" content="http://cdn.rongshen2020.com/2020928a23.png">
<meta property="article:published_time" content="2020-09-28T08:21:16.000Z">
<meta property="article:modified_time" content="2021-05-07T06:49:04.603Z">
<meta property="article:author" content="John Doe">
<meta property="article:tag" content="springCloud">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://cdn.rongshen2020.com/2020928a1.png"><meta name="generator" content="Hexo 6.1.0"></head>

<body>
  <div id="wrapper">
    <header id="header">
  <h1 id="title">
    <a href="/">rongshen</a>
  </h1>
  <nav>
    
    
      
      <a class="nav-link" href="/">Home</a>
    
      
        <span class="nav-spacer">×</span>
      
      <a class="nav-link" href="/archives">Archives</a>
    
      
        <span class="nav-spacer">×</span>
      
      <a class="nav-link" target="_blank" rel="noopener" href="https://github.com/Aaron-boom">Github</a>
    
      
        <span class="nav-spacer">×</span>
      
      <a class="nav-link" href="/2020/04/13/About-Me/">About</a>
    
    
  </nav>
</header>

    <div id="content">
      <article id="post-springcloud之Gateway" class="article article-type-post" itemprop="blogPost" itemscope>
  <div class="article-inner">
    
      <header class="article-header">
        
  
    <h2 class="article-title" itemprop="headline name">
      springcloud之Gateway
    </h2>
  


        <div class="article-meta">
          <time class="article-date" datetime="2020-09-28T08:21:16.000Z" itemprop="datePublished">2020-09-28</time>

          
        </div>
      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
      
        <blockquote>
<p>springcloud学习笔记，第7章，Gateway微服务网关。</p>
</blockquote>
<span id="more"></span>


<p>gateway：n.大门口; 门道; 出入口; (通往其他地区的) 门户; 途径; 方法; 手段;</p>
<h2 id="简介："><a href="#简介：" class="headerlink" title="简介："></a>简介：</h2><p>Gateway 是一个基于HTTP协议的restful的API网关。可以作为统一的API接入层。</p>
<p>SpringCloud Gateway是Spring cloud的一个全新项目，基于spring 5.0+springboot 2.0 和project reactor等技术开发的网关，它旨在为微服务架构提供一种简单有效的统一的API路由管理模式。</p>
<p>springcloud gateway作为spring cloud生态系统中的网关，目标是替代Zuul，在spring cloud 2.0 以上版本中，没有对新版本的zuul 2.0以上最新高性能版本进行集成，任然是使用的zuul 1.x非reactor模式的老版本。而为了提升网关的性能，springcloud gateway是基于WebFlux框架实现的，而WebFlux框架底层则使用了高性能的Reactor模式通信框架netty。</p>
<p>springcloud gateway的目标是统一的路由方式且基于Filter链的方式提供了网关基本的功能，例如：安全，监控&#x2F;指标，限流。</p>
<h3 id="源码架构："><a href="#源码架构：" class="headerlink" title="源码架构："></a>源码架构：</h3><p><img src="http://cdn.rongshen2020.com/2020928a1.png"></p>
<h3 id="能干什么？"><a href="#能干什么？" class="headerlink" title="能干什么？"></a>能干什么？</h3><ol>
<li>反向代理</li>
<li>鉴权</li>
<li>流量控制</li>
<li>熔断</li>
<li>日志监控</li>
</ol>
<h3 id="gateway在那一层呢？"><a href="#gateway在那一层呢？" class="headerlink" title="gateway在那一层呢？"></a>gateway在那一层呢？</h3><p><img src="http://cdn.rongshen2020.com/2020928a2.png"></p>
<h3 id="Gateway与Zuul的区别："><a href="#Gateway与Zuul的区别：" class="headerlink" title="Gateway与Zuul的区别："></a>Gateway与Zuul的区别：</h3><h4 id="我们为什么选择Gateway："><a href="#我们为什么选择Gateway：" class="headerlink" title="我们为什么选择Gateway："></a>我们为什么选择Gateway：</h4><ol>
<li><p>Netflix不太靠谱，zuul2.0一直跳票，迟迟不发布</p>
<p><img src="http://cdn.rongshen2020.com/2020928a3.png"></p>
</li>
<li><p>Spingcloud gateway具有如下特性：</p>
<p><img src="http://cdn.rongshen2020.com/2020928a4.png"></p>
</li>
<li><p>springcloud gateway与zuul的区别：</p>
<p><img src="http://cdn.rongshen2020.com/2020928a5.png"></p>
</li>
</ol>
<h4 id="zuul1-x模型："><a href="#zuul1-x模型：" class="headerlink" title="zuul1.x模型："></a>zuul1.x模型：</h4><p><img src="http://cdn.rongshen2020.com/2020928a6.png"></p>
<h4 id="webFlux是什么："><a href="#webFlux是什么：" class="headerlink" title="webFlux是什么："></a>webFlux是什么：</h4><p><img src="http://cdn.rongshen2020.com/2020928a7.png"></p>
<h2 id="Gateway的三大核心概念："><a href="#Gateway的三大核心概念：" class="headerlink" title="Gateway的三大核心概念："></a>Gateway的三大核心概念：</h2><p><strong>route路由</strong></p>
<p>路由是构建网关的基本模块，他由ID，目标URI(统一资源标识符)一系列的断言和过滤器组成，如果断言为true则匹配该路由。就是根据某些规则将请求发送到指定服务上。</p>
<p><strong>predicate断言</strong></p>
<p>参考的是java8.util.function.Predicate。开发人员可以匹配HTTP请求中所有内容（例如请求头和请求参数），如果请求与断言相匹配则进行路由。</p>
<p><strong>filter过滤</strong></p>
<p>指的是Spring框架中GatewayFilter的实例，使用过滤器，可以在请求被路由前或者后，对该请求进行修改。路由前后，过滤请求的。</p>
<p><strong>总体来说就是：</strong></p>
<p><img src="http://cdn.rongshen2020.com/2020928a8.png"></p>
<h2 id="Gateway工作流程："><a href="#Gateway工作流程：" class="headerlink" title="Gateway工作流程："></a>Gateway工作流程：</h2><p><img src="http://cdn.rongshen2020.com/2020928a9.png"></p>
<p><strong>解释上图：</strong>客户端spring cloud gateway发出请求。然后gateway handler mapping中找到与请求相匹配的路由，将其发送到gateway web handler。</p>
<p>​    handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑，然后返回。过滤器之间用虚线分开是因为过滤器可能会发送代理请求之前的（“pre”）或之后的（”post“）执行业务逻辑。</p>
<p>​            Filter在pre类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等。在post类型的过滤器可以做响应内容、响应头的修改，日志输出，流量监控等有非常重要的作用。</p>
<p><strong>核心逻辑就是：路由转发+执行过滤器链</strong></p>
<h2 id="使用Gateway入门配置："><a href="#使用Gateway入门配置：" class="headerlink" title="使用Gateway入门配置："></a>使用Gateway入门配置：</h2><h3 id="项目结构："><a href="#项目结构：" class="headerlink" title="项目结构："></a>项目结构：</h3><p><img src="http://cdn.rongshen2020.com/2020928a10.png"></p>
<h3 id="新建实例："><a href="#新建实例：" class="headerlink" title="新建实例："></a>新建实例：</h3><ol>
<li><p>建moudle，<code>cloud-gateway-gateway9527</code></p>
</li>
<li><p>POM</p>
<p><strong>不要web依赖模块，否则不能正常启动</strong></p>
<pre><code class="java">&lt;!--不要web依赖模块--&gt;
&lt;!--gateway--&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
    &lt;artifactId&gt;spring-cloud-starter-gateway&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;!--eureka client--&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
    &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;!--引入自己的api通用包--&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.example&lt;/groupId&gt;
    &lt;artifactId&gt;cloud-api-commons&lt;/artifactId&gt;
    &lt;version&gt;$&#123;project.version&#125;&lt;/version&gt;
&lt;/dependency&gt;
&lt;!--一般基础通用配置--&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
    &lt;scope&gt;runtime&lt;/scope&gt;
    &lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
    &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
</code></pre>
</li>
<li><p>YML</p>
<pre><code class="java">server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  # 这些网关配置就是在配置8001的端口访问
  cloud:
    gateway:
      routes:
        - id: payment_routh
          uri: http://localhost:8001
          predicates:
            - Path=/payment/get/**

        - id: payment_routh2
          uri: http://localhost:8001
          predicates:
            - Path=/payment/create

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true  #false表示不向注册中心注册自己
    fetch-registry: true #false表示自己端就是注册中心
    service-url:
      defaultZone: http://localhost:7001/eureka/
</code></pre>
<p><img src="http://cdn.rongshen2020.com/2020928a11.png"></p>
</li>
<li><p>主启动类</p>
</li>
<li><p>9527网关如何做路由映射？</p>
<ul>
<li><p>cloud-provider-payment8001看看controller的访问地址</p>
</li>
<li><p>我们目前不想暴露8001端口，希望在8001外面套一层9527</p>
</li>
</ul>
</li>
<li><p>YML新增网关配置</p>
<p><img src="http://cdn.rongshen2020.com/2020928a12.png"></p>
</li>
<li><p>测试</p>
<ol>
<li>启动7001，启动8001，启动9527网关</li>
</ol>
<p><img src="http://cdn.rongshen2020.com/2020928a13.png"></p>
<p><strong>那么这样就可以通过9527网关端口去访问8001里面的服务了。</strong></p>
</li>
</ol>
<h2 id="Gateway配置路由的两种配置方式："><a href="#Gateway配置路由的两种配置方式：" class="headerlink" title="Gateway配置路由的两种配置方式："></a>Gateway配置路由的两种配置方式：</h2><ol>
<li>在配置文件yml中配置。前面使用的就是这种方式</li>
<li>代码中注入RouteLocator的Bean<ul>
<li>配置一个id为route-name的路由规则，当访问地址为<code>http://localhost:9527/guonei</code>时会自动转发到地址：<code>http://news.baidu.com/guonei</code></li>
</ul>
</li>
</ol>
<p><img src="http://cdn.rongshen2020.com/2020928a14.png"></p>
<pre><code class="java">@Configuration
public class GatewayConfig &#123;
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)&#123;
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route(&quot;path_routh1&quot;,
                r -&gt; r.path(&quot;/guonei&quot;).uri(&quot;http://news.baidu.com/guonei&quot;))
                .build();
        return routes.build();
    &#125;
&#125;
</code></pre>
<p><img src="http://cdn.rongshen2020.com/2020928a15.png"></p>
<h2 id="Gateway配置动态路由："><a href="#Gateway配置动态路由：" class="headerlink" title="Gateway配置动态路由："></a>Gateway配置动态路由：</h2><h3 id="通过微服务名实现动态路由。"><a href="#通过微服务名实现动态路由。" class="headerlink" title="通过微服务名实现动态路由。"></a>通过微服务名实现动态路由。</h3><ol>
<li><p>默认情况下gateway会根据注册中心注册的服务列表，以注册中心上微服务名为路径创建动态路由进行转发，从而实现动态路由的功能。</p>
<p><img src="http://cdn.rongshen2020.com/2020928a16.png"></p>
</li>
<li><p>YML</p>
</li>
</ol>
<ul>
<li>需要注意的是uri的协议为lb，表示启用Gateway的负载均衡功能。lb:&#x2F;&#x2F;serviceName是spring cloud geteway在微服务中自动为我们创建的负载均衡的uri。</li>
</ul>
<ol start="3">
<li><p>测试：</p>
<ul>
<li>这时我们在写一个服务提供者8002模块，同样注册进eureka。这时我们使用微服务名进行调用：</li>
</ul>
<p><img src="http://cdn.rongshen2020.com/2020928a17.png"></p>
<ul>
<li>可以发现，这里也实现了负载均衡。</li>
</ul>
</li>
</ol>
<h2 id="Gateway中的Predicate断言："><a href="#Gateway中的Predicate断言：" class="headerlink" title="Gateway中的Predicate断言："></a>Gateway中的Predicate断言：</h2><p>spring cloud gateway将路由匹配作为spring webflux handlerMapping基础架构的一部分。spring cloud gateway包括许多的内置route predicate工厂。所有这些predicate都与HTTP请求的不同属性匹配。多个predicate工厂可以进行组合。</p>
<p>spring cloud gateway创建route对象时，使用RoutePredicateFactory创建Predicate对象，Predicate对象可以赋值给Route。Spring cloud Gateway包括许多内置的Route predicate factories。</p>
<p>所有这些route都匹配HTTP请求的不同属性。多种工厂可以组合，并通过逻辑and。</p>
<p>我们之前配置的path就是断言的一种：</p>
<p><img src="http://cdn.rongshen2020.com/2020928a18.png"></p>
<p><strong>这个断言表示，如果外部访问路径是指定路径，就路由到指定的微服务上</strong></p>
<p>可以看到，这里有一个Path，这个就是断言的一种，以下是断言的类型也可以在输出台找到：</p>
<p><img src="http://cdn.rongshen2020.com/2020928a19.png"></p>
<ol>
<li><p>After Route Predicate：</p>
<p>可以指定，只有在指定时间后，才可以路由到指定微服务。</p>
<p>获取当前时区和时间：</p>
<p><img src="http://cdn.rongshen2020.com/2020928a20.png"></p>
<ul>
<li>如果访问时间早于这个时间，那么就访问失败。</li>
</ul>
<p><img src="http://cdn.rongshen2020.com/2020928a21.png"></p>
</li>
<li><p>Before：与After类似，指定时间之前才可以访问。</p>
</li>
<li><p>Between：需要指定两个时间，逗号隔开，在他们之间的时间才可以访问。</p>
</li>
<li><p>Cookie：只有包含某些指定cookie(key,value)的请求才可以路由。</p>
</li>
<li><p>Header：只有包含指定请求头的请求,才可以路由。</p>
</li>
<li><p>host：只有指定主机的才可以访问。</p>
</li>
<li><p>method：只有指定请求才可以路由,比如get请求…</p>
</li>
<li><p>path：只有访问指定路径,才进行路由。比如访问,&#x2F;abc才路由</p>
</li>
<li><p>Query：必须带有请求参数才可以访问。</p>
</li>
</ol>
<h2 id="Gateway中的Filter过滤器："><a href="#Gateway中的Filter过滤器：" class="headerlink" title="Gateway中的Filter过滤器："></a>Gateway中的Filter过滤器：</h2><p><img src="http://cdn.rongshen2020.com/2020928a22.png"></p>
<p>**生命周期:**在请求进入路由之前,和处理请求完成,再次到达路由之前。</p>
<p><strong>种类：</strong>GatewayFilter和GlobalFilter。</p>
<ol>
<li><p>GateWayFilter,单一的过滤器：</p>
<p>与断言类似,比如闲置,请求头,只有特定的请求头才放行,反之就过滤。官网上有31个。</p>
</li>
<li><p>GlobalFilter,全局过滤器：</p>
<p>官网上有10个。</p>
<p><img src="http://cdn.rongshen2020.com/2020928a23.png"></p>
</li>
</ol>
<p><strong>自定义过滤器：</strong></p>
<p>实现两个接口</p>
<pre><code class="java">@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered &#123;
    @Override
    public Mono&lt;Void&gt; filter(ServerWebExchange exchange, GatewayFilterChain chain) &#123;

        log.info(&quot;*********come in MyLogGateWayFilter: &quot;+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst(&quot;username&quot;);
        if(StringUtils.isEmpty(username))&#123;
            log.info(&quot;*****用户名为Null 非法用户,(┬＿┬)&quot;);
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//给人家一个回应
            return exchange.getResponse().setComplete();
        &#125;
        return chain.filter(exchange);
    &#125;

    @Override
    public int getOrder() &#123;
        return 0;
    &#125;
&#125;
</code></pre>
<p>测试链接：<code>localhost:9527/payment/lb?uname=z3</code></p>
<p>这个自定义过滤器能干嘛？可以全局日志记录和统一网关鉴权。</p>
<p>然后启动服务,即可,因为过滤器通过@Componet已经加入到容器了。</p>

      
    </div>
    
    
    <div class="article-category">
      
        <b>Categories:</b>
        <a class="article-category-link" href="/categories/spring-cloud/">spring cloud</a>
      
      
        <br/>
      
      
        <b>Tags:</b>
        <a class="article-tag-none-link" href="/tags/springCloud/" rel="tag">springCloud</a>
      
    </div>
    
    
  </div>
</article>

  
<nav id="article-nav" class="article-nav">
  
    <a href="/2020/09/29/springcloud%E4%B9%8Bconfig%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/" id="article-nav-newer" class="article-nav-link-wrap newer">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          springcloud之config分布式配置中心
        
      </div>
    </a>
  
  
    <a href="/2020/09/27/springcloud%E4%B9%8BHystrix/" id="article-nav-older" class="article-nav-link-wrap older">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">
        
          springcloud之Hystrix
        
      </div>
    </a>
  
</nav>






    </div>
  </div>
  




<div id="settings-container">
  <div id="dark-mode">dark</div>
  <div id="sans-font">sans</div>
</div>
<script type="text/javascript">
let d=document,r=d.documentElement.style,f=r.setProperty.bind(r),l=localStorage,s=l.getItem('s')||(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches),n=l.getItem('n'),m=d.getElementById("dark-mode"),b=()=>{f('--bg-color','#fafafa');f('--code-bg-color','#f4f4f4');f('--text-color','#212121');f('--secondary-color','#808080');f('--tertiary-color','#b0b0b0');f('--link-color','#b5c8cf');f('--link-hover-color','#618794');f('--link-bg-color','#dae4e7');f('--selection-color','#dae4e7');m.innerHTML="dark"},c=()=>{f('--bg-color','#212121');f('--code-bg-color','#292929');f('--text-color','#fff');f('--secondary-color','#c0c0c0');f('--tertiary-color','#6e6e6e');f('--link-color','#4d6b75');f('--link-hover-color','#96b1bb');f('--link-bg-color','#5d828e');f('--selection-color','#acc1c9');m.innerHTML="light"},o=d.getElementById("sans-font"),e=()=>{f('--body-stack','"Lora", "Georgia", "Times New Roman", serif');o.innerHTML="sans"},g=()=>{f('--body-stack','"Lato", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "Verdana", sans-serif');o.innerHTML="serif"};m.onclick=()=>{if(s==2){s=1;l.setItem('s',s);c()}else{s=2;l.setItem('s',s);b()}};o.onclick=()=>{if(n==2){n=1;l.setItem('n',n);g()}else{n=2;l.setItem('n',n);e()}};if(!s){s=2;l.setItem('s',2)};if(s==1){c()};if(!n){n=2;l.setItem('n',2)};if(n==1){g()};
</script>




</body>
</html>
